package com.imooc.course.file.controller.admin;

import com.alibaba.fastjson.JSON;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.vod.model.v20170321.GetMezzanineInfoResponse;
import com.aliyuncs.vod.model.v20170321.GetVideoPlayAuthResponse;
import com.imooc.course.file.form.FileForm;
import com.imooc.course.server.dto.FileDto;
import com.imooc.course.server.dto.ResponseDto;
import com.imooc.course.server.enums.FileUseEnum;
import com.imooc.course.server.service.FileService;
import com.imooc.course.server.utils.CopyUtil;
import com.imooc.course.server.utils.VodUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.*;

@RestController
@RequestMapping("/vod/admin")
public class VodController {

    private static final Logger log = LoggerFactory.getLogger(OssController.class);
    public static final String BUSINESS_NAME = "上传至阿里云VOD视频点播服务";

    @Value("${vod.regionId}")
    private String regionId;

    // 阿里云主账号AccessKey拥有所有API的访问权限，风险很高。强烈建议您创建并使用RAM用户进行API访问或日常运维，请登录RAM控制台创建RAM用户。
    @Value("${vod.accessKeyId}")
    private String accessKeyId;//子RAM用户accessKeyId

    @Value("${vod.accessKeySecret}")
    private String accessKeySecret;//子RAM用户accessKeySecret

    @Value("${vod.cateId}")
    private Long cateId;

    @Value("${vod.templateGroupId}")
    private String templateGroupId;

    @Resource(name = "fileService")
    private FileService fileService;

    @PostMapping("/upload")
    public ResponseDto ossUpload(@RequestParam MultipartFile shard, String param) throws Exception {
        //将接收到的文件转换为流
        InputStream in = shard.getInputStream();

        //将字符串参数还原为对象并拼接文件访问路径
        FileForm fileForm = JSON.parseObject(param, FileForm.class);
        FileUseEnum useEnum = FileUseEnum.getByCode(fileForm.getUse());
        String dir = useEnum.name().toLowerCase();

        String fileName = fileForm.getName();//存储到阿里视频云点播服务时用的title
        String path = new StringBuffer(dir)//存储到阿里视频云点播服务时使用的path
                .append("/")
                .append(fileForm.getName())
                .toString();

        //失败3次放弃上传。这里用id传值显得不规范。
        if ("3".equals(fileForm.getId())) {
            this.removeFile(fileForm);
            FileDto dto = new FileDto();
            dto.setPath("");
            return ResponseDto.fail().setContent(dto);
        }

        Integer code = this.vod(in, fileForm, path, fileName);

        FileDto fileDto = CopyUtil.copy(fileForm, FileDto.class);

        if (code == 0) {

            log.info("开始保存文件记录");
            fileDto.setPath(path);
            fileDto.setVod(fileForm.getVod());
            fileService.save(fileDto);

            fileDto.setPath(fileForm.getPath());
            return ResponseDto.success().setCode(String.valueOf(code)).setContent(fileDto);
        } else {
            fileDto.setShardIndex(code);
            fileDto.setPath("");
            return ResponseDto.success().setCode(String.valueOf(code)).setContent(fileDto);
        }


    }

    private int vod(InputStream in, FileForm fileForm, String path, String fileName) {
        int temp = 0;
        try {
            VodUtil vodUtil = new VodUtil();
            VodUtil.Config config = vodUtil.new Config();
            config.regionId = regionId;
            config.accessKeyId = accessKeyId;
            config.accessKeySecret = accessKeySecret;
            config.templateGroupId = templateGroupId;
            config.title = fileName;
            config.fileName = path;
            config.cateId = cateId;
            VodUtil.ExecuteUpload executeUpload = vodUtil.new ExecuteUpload();
            vodUtil.executeUploadToApsaraVideo(executeUpload,config,in);
            DefaultAcsClient vodClient = executeUpload.getVodClient();
            String videoId = executeUpload.getVideoId();
            GetMezzanineInfoResponse info = vodUtil.getMezzanineInfo(vodClient, videoId);
            fileForm.setVod(videoId);
            fileForm.setPath(info.getMezzanine().getFileURL());
            // 关闭inputStream。
            in.close();
        } catch (Exception e) {
            temp = fileForm.getShardIndex();
            e.printStackTrace();
        }
        return temp;
    }

    private void removeFile(FileForm fileForm) {
        // 删除阿里云视频点播服务中储存的视频。
        VodUtil vodUtil = new VodUtil();
        try {
            vodUtil.deleteVideo(this.createClient(vodUtil), fileForm.getVod());
        } catch (Exception e) {
            log.error("删除vod视频失败",e);
            e.printStackTrace();
        }
        fileService.removeByKey(fileForm.getKey());
    }

    @GetMapping("/check/{key}")
    public ResponseDto checkShardIndex(@PathVariable("key") String key) {
        FileDto fileDto = fileService.getByShardIndex(key);
        if (fileDto == null) {
            return ResponseDto.success().setContent(null);
        }
        String videoId = !StringUtils.isEmpty(fileDto.getVod()) ? fileDto.getVod() : null;
        if (videoId != null) {
            VodUtil vodUtil = new VodUtil();
            GetMezzanineInfoResponse info = null;
            try {
                info = vodUtil.getMezzanineInfo(this.createClient(vodUtil), videoId);
            } catch (Exception e) {
                log.error("无法获取视频点播服务源信息",e);
                e.printStackTrace();
                return ResponseDto.fail();
            }
            fileDto.setPath(info.getMezzanine().getFileURL());
            return ResponseDto.success().setContent(fileDto);
        } else {
            fileService.removeByKey(fileDto.getKey());
            return ResponseDto.success().setContent(null);
        }
    }

    @PostMapping("/get-auth")
    public ResponseDto getAuthByVod(String videoId) {
        VodUtil vodUtil = new VodUtil();
        GetVideoPlayAuthResponse response;
        try {
            response = vodUtil.getVideoPlayAuth(this.createClient(vodUtil),videoId);
        } catch (Exception e) {
            log.error("无法获取视频点播服务凭证",e);
            e.printStackTrace();
            return ResponseDto.fail();
        }
        return ResponseDto.success().setContent(response.getPlayAuth());
    }

    //将MultipartFile转换为File
    private File convertForFile(MultipartFile mf) throws IOException {

        File file = new File(mf.getOriginalFilename());

        InputStream in = mf.getInputStream();
        OutputStream out = new FileOutputStream(file);

        byte[] b = new byte[10 * 1024 * 1024];
        int len = 0;
        while ((len = in.read(b)) != -1) {
            out.write(b,0,len);
        }

        in.close();
        out.close();
        return file;
    }

    private DefaultAcsClient createClient(VodUtil vodUtil) {
        VodUtil.ExecuteUpload executeUpload = vodUtil.new ExecuteUpload();
        DefaultAcsClient client;
        RuntimeException runtimeError = null;
        for (int i = 0; i < 4 ; i++) {
            try {
                client = executeUpload.initVodClient(regionId, accessKeyId, accessKeySecret);
                return client;
            } catch (ClientException e) {
                if (i == 3) {
                    runtimeError = new RuntimeException("连接阿里云视频点播服务出错", e);
                } else {
                    log.info("failed: 连接阿里云视频点播服务失败，重试第"+(i+1)+"次；",e.getErrMsg());
                    continue;
                }
            }
        }
        log.error("failed: 无法连接到阿里云视频点播服务；",runtimeError);
        throw runtimeError;
    }

}
